#include "dataBase.h"

/**
 * @msg: 在id_name.yaml中搜索用户的简单信息并保存在config中
 * @param {std::string lable(查找的标签), std::string key(查找的内容), studentConfig& config} 
 * @return: 改用户的map索引
 */
int searchList::searchUser(std::string lable, std::string key, studentConfig& config)
{
    for(int i = 0; i < this->numofMap(); i++)
    {
        if(key == this->readList(i, lable))
        {
            config.id = this->readList(i, "id");
            config.name = this->readList(i, "name");
            config.password = this->readList(i, "password");
            config.username = this->readList(i, "username");
            config.major = this->readList(i, "major");
            config.grade = this->readList(i, "grade");
            config._class = this->readList(i, "class");
            return i;
        }
    }
    config = {"","","","","","",""};
    return -1;
}

bool searchList::update(studentConfig new_config)
{
    studentConfig temp_config;
    int index = this->searchUser("id", new_config.id, temp_config);
    if(index >= 0)
    {
        //如果需要更新的用户已存在
        this->writeList(index, "name", new_config.name);
        this->writeList(index, "username", new_config.username);
        this->writeList(index, "password", new_config.password);
        this->writeList(index, "major", new_config.major);
        this->writeList(index, "grade", new_config.grade);
        this->writeList(index, "class", new_config._class);
    }
    else
    {
        index = this->numofMap();
        this->writeList(index, "name", new_config.name);
        this->writeList(index, "id", new_config.id);
        this->writeList(index, "username", new_config.username);
        this->writeList(index, "password", new_config.password);
        this->writeList(index, "major", new_config.major);
        this->writeList(index, "grade", new_config.grade);
        this->writeList(index, "class", new_config._class);
    }
    return true;
}

/**
 * @msg: 设置成绩数据库班级数据文件路径
 * @param {std::string major, std::string grade, std::string _class} 
 * @return: int(索引)
 */
void subjectConfig::setClass(std::string major, std::string grade, std::string _class)
{
    this->loadFile("./data/scores/" + major + "/" + grade + "/" + _class + "/config.yaml");
    std::cout << "loading file: " << this->currentPath() << std::endl;
}

/**
 * @msg: 给数据库班级数据文件添加科目描述
 * @param {std::string subject, int maxscore, int passscore, std::string examedate} 
 * @return: void
 */
void subjectConfig::addSubject(std::string subject, int maxscore, int passscore, std::string examedate)
{
    for(size_t i = 0; i < numofMap(); i++)
    {
        if(this->readList(i, "subject") == subject)
        {
            this->writeList(i, "maxscore", std::to_string(maxscore));
            this->writeList(i, "passscore", std::to_string(passscore));
            this->writeList(i, "examdate", examedate);
            std::cout << "modifying subject config." << std::endl;
            return;
        }
    }
    //如果没有这门科目则新建
    this->writeList(this->numofMap(), "subject", subject);
    this->writeList(this->numofMap(), "maxscore", std::to_string(maxscore));
    this->writeList(this->numofMap(), "passscore", std::to_string(passscore));
    this->writeList(this->numofMap(), "examdate", examedate);
    std::cout << "adding subject config." << std::endl;
}

/**
 * @msg: 返回用户在yaml文件中map的索引
 * @param {void} 
 * @return: int(索引)
 */
int DataBaseRW::index()
{
    static int indexnum;
    if(userisChanged())
    {
        //找不到就放在最后
        indexnum = this->numofMap();
        for(int i = 0; i < this->numofMap(); i++)
        {
            if(readList(i, "id") == this->student_config.id)
            {
                indexnum = i;
                break;
            }
        }
    }
    return indexnum;
}

/**
 * @msg: 查询读写对象是否已改变
 * @param {void} 
 * @return: int(索引)
 */
bool DataBaseRW::userisChanged()
{
    if(this->user_is_changed)
    {
        this->user_is_changed = false;
        return true;
    }
    return false;
}

/**
 * @msg: 设置数据库读写插件的读写对象
 * @param {studentConfig config} 
 * @return: bool
 */
bool DataBaseRW::setUser(studentConfig config)
{
    this->student_config = config;
    std::string file_path = "./data/config" + config.major + "/" + config.grade + "/" + config._class + ".yaml";
    this->loadFile(file_path);
    std::cout << "loading file: " << file_path << std::endl; 
    this->user_is_changed = true;
}

/**
 * @msg: 读取用户保存在数据文件中的某项具体数据
 * @param {std::string lable(需要读取的数据的标签)} 
 * @return: std::string(读取到的数据)
 */
std::string DataBaseRW::readLable(std::string lable)
{
    return this->readList(this->index(), lable);
}

/**
 * @msg: 修改用户保存在数据文件中的某项具体数据
 * @param {std::string lable(需要读取的数据的标签), std::string content(需要写入的数据)} 
 * @return: bool
 */
bool DataBaseRW::writeLable(std::string lable, std::string content)
{
    return this->writeList(this->index(), lable, content);
}

/**
 * @msg: 提取保存的数据到studentConfig结构体
 * @param {void} 
 * @return: bool
 */
bool StudentData::read()
{
    std::cout << "reading student's data...";
    this->student_config.sex = this->readLable("sex");
    this->student_config.phone = this->readLable("phone");
    this->student_config.email = this->readLable("email");
    this->student_config.birthday = this->readLable("birthday");
    this->student_config.pid = this->readLable("pid");
    this->student_config.address = this->readLable("address");
    std::cout << " finished" << std::endl;
}

/**
 * @msg: 保存studentConfig结构体的数据到数据库
 * @param {void} 
 * @return: bool
 */
bool StudentData::save(std::string config_string)
{
    this->unzip(config_string);
    std::cout << "saving student's data...";
    this->writeLable("name", this->student_config.name);
    this->writeLable("id", this->student_config.id);
    this->writeLable("phone", this->student_config.phone);
    this->writeLable("email", this->student_config.email);
    this->writeLable("sex", this->student_config.sex);
    this->writeLable("birthday", this->student_config.birthday);
    this->writeLable("pid", this->student_config.pid);
    this->writeLable("address", this->student_config.address);
    //设置默认登录用户名和密码
    this->student_config.username = this->student_config.id;
    this->student_config.password = this->student_config.birthday;
    std::cout << " finished" << std::endl;
}

/**
 * @msg: 将所有信息压缩成一帧
 * @param {void} 
 * @return: std::string
 */
std::string StudentData::zip()
{
    std::string frame = 
        this->student_config.name + " " +
        this->student_config.id + " " +
        this->student_config._class + " " +
        this->student_config.grade + " " +
        this->student_config.major + " " +
        this->student_config.phone + " " +
        this->student_config.email + " " +
        this->student_config.sex + " " +
        this->student_config.birthday + " " +
        this->student_config.pid + " " +
        this->student_config.address;
    return frame;
}

/**
 * @msg: 将所有信息解压并保存到studentConfig中
 * @param {void} 
 * @return: std::string
 */
void StudentData::unzip(std::string frame)
{
    this->student_config.name = peekString(frame, 1);
    this->student_config.id = peekString(frame, 2);
    this->student_config._class = peekString(frame, 3);
    this->student_config.grade = peekString(frame, 4);
    this->student_config.major = peekString(frame, 5);
    this->student_config.phone = peekString(frame, 6);
    this->student_config.email = peekString(frame, 7);
    this->student_config.sex = peekString(frame, 8);
    this->student_config.birthday = peekString(frame, 9);
    this->student_config.pid = peekString(frame, 10);
    this->student_config.address = peekString(frame, 11);
}

/**
 * @msg: 获取学生信息备份
 * @param {void} 
 * @return: studentConfig
 */
studentConfig StudentData::getstudentConfig()
{
    studentConfig res = this->student_config;
    return res;
}

/**
 * @msg: 保存studentConfig结构体的数据到数据库
 * @param {void} 
 * @return: bool
 */
bool StudentDataManage::save(std::string config_string)
{
    if( peekString(config_string, 3) != this->student_config._class || 
        peekString(config_string, 4) != this->student_config.grade  ||
        peekString(config_string, 5) != this->student_config.major
    )
    {
        //如果学生的班级信息发生改变，需要将其从原来班级中去除
        removeStudentFromClass();
        std::cout << "warning: student's class is changed" << std::endl;
    }
    this->unzip(config_string);
    //重新打开数据库文件
    this->setUser(this->student_config);
    std::cout << "saving student's data...";
    this->writeLable("name", this->student_config.name);
    this->writeLable("id", this->student_config.id);
    this->writeLable("class", this->student_config._class);
    this->writeLable("grade", this->student_config.grade);
    this->writeLable("major", this->student_config.major);
    this->writeLable("phone", this->student_config.phone);
    this->writeLable("email", this->student_config.email);
    this->writeLable("sex", this->student_config.sex);
    this->writeLable("birthday", this->student_config.birthday);
    this->writeLable("pid", this->student_config.pid);
    this->writeLable("address", this->student_config.address);
    //设置默认登录用户名和密码
    this->student_config.username = this->student_config.id;
    this->student_config.password = this->student_config.birthday;
    std::cout << " finished" << std::endl;
}

/**
 * @msg: 添加学生
 * @param {std::string config_string} 
 * @return: void
 */
void StudentDataManage::addStudent(std::string config_string)
{
    this->unzip(config_string);
    this->setUser(this->student_config);
    std::cout << "setting" << std::endl;
    this->save(config_string);
}

/**
 * @msg: 从班级中删除学生(只有管理员权限)
 *       管理员可能会改变学生的班级信息
 *       如果不把学生从当前班级文件中删除
 *       会出现重复 占用班级文件
 * @param {std::string config_string} 
 * @return: void
 */
void StudentDataManage::removeStudentFromClass()
{
    this->deleteOneMap(index());
    std::cout << "deleted" << std::endl;
}
